# FROM 指定基础镜像: FROM <image>:<tag> [as other_name] tag可选，不写默认latest
# as other_name是可选的，通常用于多阶段构建（有利于减少镜像大小），使用是通过--from other_name使用,例如COPY --from other_name
FROM openjdk:8-jdk-alpine
# LABEL 镜像描述信息，有多种写法
# LABEL指令是以键值对形式给镜像添加元数据信息，可以替代MAINTAINER指令，会集成基础镜像中的LABEL指令，相同的key会被覆盖
LABEL author="song"
LABEL describe="test image"
# 或
LABEL author="song" describe="test image"
# 或
LABEL author="song" \
      describe="test image"
# MAINTAINER 添加作者信息，不建议使用
MAINTAINER song
# COPY 从构建主机复制文件到镜像中
# COPY <src> <dest>
# src指要复制的文件或目录，支持通配符，src是目录，其内部的文件和子目录都会递归复制，但src目录本身不会被复制，如果制定了多个src或者使用了通配符，dest必须是一个目录且以'/'结尾
# dest指目标路径，即镜像中的文件或目录，dest如果不存在会被自动创建，包括其父目录也会自动创建
# COPY ["<src>", "<src>", ... "<dest>"]
COPY bmp-file-service-1.0-RELEASE.jar app.jar
COPY testFile /opt/
COPY testDir /opt/testDir
# ADD 从构建主机复制文件到镜像中
# ADD 类似于 COPY，但是ADD支持tar文件和URL路径
# ADD <src> <dest>
# src如果是一个压缩文件tar，会被解压为一个目录，如果是通过URL下载一个文件不会被解压，<src>如果是多个，或使用了通配符，则<dest>必须是以'/'结尾的目录，否则<src>会被作为一个普通文件，<src>的内容将被写入到<dest>
ADD bmp-file-service-1.0-RELEASE.jar app.jar
# WORKDIR 设置工作目录，类型于cd命令，改变当前的目录域
# 如果设置的目录不存在会自动创建，包括其父目录
# 一个Dockefile中WORKDIR可以出现多次，也可以使用相对路径，相对路径基于上一个WORKDIR，WORKDIR也可以调用ENV指定的变量
WORKDIR /home/app
# ENV 设置镜像中的变量，可以一次设置多个
# 使用变量方式 $username ${username} ${username:-default admin}设置一个默认值，无值时使用默认值 ${username:+default admin}设置一个默认值，无论有无值都使用默认值
ENV username admin
ENV username=admin password=admin
# ARG 指定环境变量，用于构建过程
# ARG指令定义的参数，在构建过程以docker build --build-arg test_name=test 形式赋值
# 若ARG中没有设置默认值，构建时将抛出警告：[Warning] One or more build-args..were not consumed
ARG name
ARG name=admin
# USER 设置启动容器的用户
# USER UID 可以设置用户名或用户ID
USER admin
# RUN 镜像构建时执行的命令
# shell语法：RUN command1 && command2
# exec语法：RUN ["executable","param1","[param2]"]
# RUN 在下一次建构期间，会优先查找本地缓存，若不想使用缓存可以通过--no-cache解除，docker build --no-cache
# RUN 指令指定的命令是否可以执行取决于 基础镜像
# shell形式：默认使用/bin/sh -c 执行后面的command，可以使用 && 或 \ 连接多个命令，
# exec形式： exec形式被解析为JSON序列，这意味着必须使用双引号 ""，与 shell 形式不同，exec 形式不会调用shell解析。但exec形式可以运行在不包含shell命令的基础镜像中，例如：RUN ["echo","$HOME"] ;这样的指令 $HOME并不会被解析，必须RUN ["/bin/sh","-c","echo $HOME"]
# 设置时区
RUN echo 'Asia/Shanghai' >/etc/timezone
# 指定监听端口实现与外部通信，这里并不会直接暴露出去，须在docker run容器时-P指定
# EXPOSE <port>/<protocol> port端口号，protocol协议类型(tcp/udp/http/https)，默认tcp，例如 80/http 2379/tcp
EXPOSE 8242
# VOLUME 实现挂载，将宿主机的指定目录挂载到容器中，一般不在Dockerfile指定，在容器启动时指定
VOLUME /home/data /opt
# CMD 为容器设置默认启动命令和参数
# shell方式：CMD command param1 param2 ...
# exec方式：CMD ["executable","param1","param2"]
# CMD运行结束后容器将终止，CMD可以被docker run后面的命令覆盖，一个Dockerfile只有顺序向下的最后一个CMD生效
# 语法1，shell形式，默认/bin/sh -c，此时运行为shell的子进程，能使用shell的操作符(if、环境变量、? *通配符等)，注意：进程在容器中的 PID != 1，这意味着该进程并不能接受到外部传入的停止信号docker stop
# 语法2，exec形式CMD ["executable","param1","param2"]，不会以/bin/sh -c运行（非shell子进程），因此不支持shell的操作符，若运行的命令依赖shell特性，可以手动启动CMD ["/bin/sh","-c","executable","param1"...]
# 语法3，exec形式CMD ["param1","param2"]，一般结合ENTRYPOINT指令使用
CMD echo 1
# ENTRYPOINT 用于为容器指定默认运行程序或命令
# 与CMD类似，但存在区别，主要用于指定启动的父进程，PID=1
# ENTRYPOINT设置默认命令不会被docker run命令行指定的参数覆盖，指定的命令行会被当做参数传递给ENTRYPOINT指定的程序
# docker run命令的 --entrypoint选项可以覆盖ENTRYPOINT指令指定的程序，一个Dockerfile中可以有多个ENTRYPOINT，但只有最后一个生效，ENTRYPOINT主要用于启动父进程，后面跟的参数被当做子进程来启动
ENTRYPOINT ["java", "-jar", "/home/app/app.jar"]
# 为镜像添加触发器
# ONBUILD可以为镜像添加一个触发器，其参数可以是任意一个Dockerfile指令
# ONBUILD <dockerfile_exec> <param1> <param2>
# 该指令，对于使用该Dockerfile构建的镜像并不会生效，只有当其他Dockerfile以当前镜像作为基础镜像时被触发
ONBUILD RUN echo 1
# STOPSIGNAL 设置停止时要发送给PID=1进程的信号
# 主要的目的是为了让容器内的应用程序在接收到signal之后可以先做一些事情，实现容器的平滑退出，如果不做任何处理，容器将在一段时间之后强制退出，会造成业务的强制中断，这个时间默认是10s
# 默认的停止信号为：SIGTERM，也可以通过docker run -s指定
STOPSIGNAL signal
# HEALTHCHECK 指定容器健康检查命令
# 当在一个镜像指定了 HEALTHCHECK 指令后，用其启动容器，初始状态会为 starting，在 HEALTHCHECK 指令检查成功后变为 healthy，如果连续一定次数失败，则会变为 unhealthy
# HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK --interval=5s --timeout=3s --retries=3 \
    CMD curl -fs http://localhost/ || exit 1        # 如果执行不成功返回1
# SHELL 指定shell形式的默认值
# SHELL 指令可以指定 RUN、ENTRYPOINT、CMD 指令的 shell，Linux 中默认为["/bin/sh", "-c"] ，Windows默认["CMD","/S","/C"]
# 示例，比如在Windows时，默认shell是["CMD","/S","/C"]
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
# docker调用的是cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
# 这样虽然没有调用cmd.exe 但写起来比较麻烦，所以可以通过SHELL  ["powershell", "-command"] 这样省去前边的powershell -command
SHELL ["/bin/bash","-c"]
SHELL ["powershell", "-command"]